package cz.muni.fi.pa165.sme.web.system;

import org.apache.wicket.Session;
import org.apache.wicket.authroles.authentication.AuthenticatedWebSession;
import org.apache.wicket.authroles.authorization.strategies.role.Roles;
import org.apache.wicket.injection.Injector;
import org.apache.wicket.request.Request;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.AuthenticationException;

/** @author jirankova */
public class SportManagerAuthenticatedSession extends AuthenticatedWebSession {

	private static final long serialVersionUID = 3355101222374558750L;


	@SpringBean(name = "authenticationManager")
	private AuthenticationManager authenticationManager;

	public SportManagerAuthenticatedSession(Request request) {
		super(request);
		injectDependencies();
		ensureDependenciesNotNull();
	}

	@Override
	public boolean authenticate(final String login, final String password) {
		boolean authenticated; //default set to false
		try {
			Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(login, password));
			SecurityContextHolder.getContext().setAuthentication(authentication);
			authenticated = authentication.isAuthenticated();
		} catch (AuthenticationException e) {
			authenticated = false;
		}
		return authenticated;
	}

	@Override
	public Roles getRoles() {
		Roles roles = new Roles();
		getRolesIfSignedIn(roles);
		return roles;
	}

	public static SportManagerAuthenticatedSession get() {
		return (SportManagerAuthenticatedSession) Session.get();
	}

	/**
	 * Sign the user out, evict caches and replace the session.
	 */
	public void signOut() {
		super.signOut();

		getApplication().getSecuritySettings().getAuthenticationStrategy().remove();
		SecurityContextHolder.getContext().setAuthentication(null);

		replaceSession();
	}

	private void getRolesIfSignedIn(Roles roles) {
		if (isSignedIn()) {
			Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
			addRolesFromAuthentication(roles, authentication);
		}
	}

	private void addRolesFromAuthentication(Roles roles, Authentication authentication) {
		for (GrantedAuthority authority : authentication.getAuthorities()) {
			roles.add(authority.getAuthority());
		}
	}

	private void ensureDependenciesNotNull() {
		if(authenticationManager == null) {
			throw new IllegalStateException("Authentication manager is not set.");
		}
	}

	private void injectDependencies() {
		Injector.get().inject(this);
	}
}
